﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using System.Reflection;
using System.Data;

namespace TransactionServer.OSActivities77
{
    using TransactionServer.General_Classes;

    public class OSConnector77 : ISystemConnector, IDisposable
    {
        public string connection;
        private dynamic _OSConnection;
        private dynamic v77comConnector;
        private string connenctionString;
        private bool disposed = false;

        public OSConnector77(Dictionary<string, string> settings) : base(settings) { }

        private object _Metadata;
        private object Metadata
        {
            get
            {
                if (_Metadata == null)
                {
                    _Metadata = GetObjectProperty(OSConnection, "Метаданные");
                }
                return _Metadata;
            }
        }

        /// <summary>
        /// connection to 1C
        /// </summary>
        private dynamic OSConnection
        {
            get
            {
                if (_OSConnection == null)
                {
                    v77comConnector = Type.GetTypeFromProgID("V77.Application");
                    _OSConnection = Activator.CreateInstance(v77comConnector);
                    connenctionString = String.Empty;


                    connenctionString = String.Format(@"/d {0} /n {1} /p {2}", 
                        settings.ContainsKey("path") ? settings["path"] : String.Empty, 
                        settings.ContainsKey("user") ? settings["user"] : String.Empty, 
                        settings.ContainsKey("password") ? settings["password"] : String.Empty);

                    bool ok = (Boolean)_OSConnection.Initialize(_OSConnection.RMTrade(), connenctionString, "NO_SPLASH_SHOW");

                    /*if (!ok)
                    {
                        throw new Exception("Error initializing connection to 1C 7.7");
                    }*/
                }
                return _OSConnection;
            }
            // to delete, test purpose only
            set
            {
                _OSConnection = value;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    close();
                }
                // Free your own state (unmanaged objects).
                // Set large fields to null.
                disposed = true;
            }
        }

        /// <summary>
        /// Gets next events from 1C
        /// </summary>
        /// <returns>Next event if any</returns>
        public override Event getNextEvent()
        {
            /*
             * 	 МенеджерЗаписи = РегистрыСведений.MSDto1C_События.СоздатьМенеджерЗаписи();
  Выборка = РегистрыСведений.MSDto1C_События.Выбрать();
  Пока Выборка.Следующий() Цикл
    МенеджерЗаписи = Выборка.ПолучитьМенеджерЗаписи();      
    МенеджерЗаписи.Прочитать();
	Сообщить(МенеджерЗаписи.Дата);
	Сообщить(МенеджерЗаписи.СистемноеПредставление); 
	Сообщить(МенеджерЗаписи.ТипСобытия); 
	Сообщить(МенеджерЗаписи.ТипОбъекта); 
	Сообщить(МенеджерЗаписи.Событие); 		
    МенеджерЗаписи.Удалить();
  Конеццикла; 

             * */

            var manager = OSConnection.CreateObject(EntityName.Catalog + ".MSDto1C_События");
            var selection = InvokeObjectMethod(manager, "ВыбратьЭлементы");

            var serializer = new XmlSerializer(typeof(Event));

            if ((double)InvokeObjectMethod(manager, "ПолучитьЭлемент") == 1.0)
            {
                //recordmanager = InvokeObjectMethod(selection, "ПолучитьМенеджерЗаписи");
                //InvokeObjectMethod(recordmanager, "Прочитать");

                string xml = (string)GetObjectProperty(manager, "Событие");
                StringReader sr = new StringReader(xml);
                Event evnt = (Event)serializer.Deserialize(sr);

                InvokeObjectMethod(manager, "Удалить");

                return evnt;
            }
            else
            {
                return null;
            }
        }
        
        /// <summary>
        /// Gets list of entities in 1C 7.7 configuration
        /// </summary>
        /// <returns></returns>
        public override List<string> getEntities()
        {
            List<string> entities = new List<string>();
            string[] types = new string[] { EntityName.Catalog, EntityName.Document, EntityName.Registry };

            foreach (var type in types)
            {
                double count = (double)InvokeObjectMethod(Metadata, type, null);

                for (int i = 1; i <= count; i++)
                {
                    object list = InvokeObjectMethod(Metadata, type, new object[] { i });
                    string entityname = type + "." + (string)GetObjectProperty(list, "Идентификатор");
                    entities.Add(entityname);

                    if (type == EntityName.Document)
                    {
                        entities.Add(String.Format("{0}.{1}", EntityName.TablePart, (string)GetObjectProperty(list, "Идентификатор")));
                    }
                }
            }

            entities.Sort();

            return entities;
        }

        /// <summary>
        /// Gets list of attributes for specified entity
        /// </summary>
        /// <param name="entity">The name of entity (for example Справочник.Контрагенты)</param>
        /// <returns></returns>
        public override List<string> getAttributes(string entity)
        {
            string entitytype = entity.Split(new char[] { '.' })[0];
            string entityname = entity.Split(new char[] { '.' })[1];

            string[] attrtypes = new string[] { "Измерение", "Ресурс", "Реквизит" };

            object Metadata = GetObjectProperty(OSConnection, "Метаданные");
            object list = null;

            List<string> result = new List<string>();

            if (entitytype == EntityName.Catalog)
            {

                list = InvokeObjectMethod(Metadata, entitytype, entityname);

                double count = (double)InvokeObjectMethod(list, "Реквизит");

                for (int i = 1; i <= count; i++)
                {
                    object attribute = InvokeObjectMethod(list, "Реквизит", i);
                    result.Add((string)GetObjectProperty(attribute, "Идентификатор"));
                }

                result.Add("Код");
                result.Add("Наименование");
                result.Add("Родитель");
                result.Add("Владелец");
            }
            else if (entitytype == EntityName.Document)
            {
                list = InvokeObjectMethod(Metadata, entitytype, entityname);

                double count = (double)InvokeObjectMethod(list, "РеквизитШапки");

                for (int i = 1; i <= count; i++)
                {
                    object attribute = InvokeObjectMethod(list, "РеквизитШапки", i);
                    result.Add((string)GetObjectProperty(attribute, "Идентификатор"));
                }

                result.Add("НомерДок");
                result.Add("ДатаДок");

                double reqCount = (double)InvokeObjectMethod(Metadata, "ОбщийРеквизитДокумента");

                for (int i = 1; i <= reqCount; i++)
                {
                    object attribute = InvokeObjectMethod(Metadata, "ОбщийРеквизитДокумента", i);
                    result.Add((string)GetObjectProperty(attribute, "Идентификатор"));
                }

            }
            else if (entitytype == EntityName.Registry)
            {

                list = InvokeObjectMethod(Metadata, entitytype, entityname);

                foreach (string attrtype in attrtypes)
                {
                    double count = (double)InvokeObjectMethod(list, attrtype, null);

                    for (int i = 1; i <= count; i++)
                    {
                        object attribute = InvokeObjectMethod(list, attrtype, i);
                        result.Add(String.Format("{0}.{1}", attrtype, (string)GetObjectProperty(attribute, "Идентификатор")));
                    }
                }

            }
            else if (entitytype == EntityName.TablePart)
            {

                list = InvokeObjectMethod(Metadata, EntityName.Document, entityname);

                double count = (double)InvokeObjectMethod(list, "РеквизитТабличнойЧасти");

                for (int i = 1; i <= count; i++)
                {
                    object attribute = InvokeObjectMethod(list, "РеквизитТабличнойЧасти", i);
                    result.Add((string)GetObjectProperty(attribute, "Идентификатор"));
                }

                result.Add(EntityName.Document);
            }

            result.Sort();
            return result;
        }

        /// <summary>
        /// Gets COM object that represents entity converted from Entity type of connector
        /// </summary>
        /// <param name="ent">Entity to convert to COM Object</param>
        /// <returns></returns>
        public object ConvertFrom(Entity ent)
        {
            string entitytype = ent.Name.Split(new char[] { '.' })[0];
            string entityname = ent.Name.Split(new char[] { '.' })[1];
            object primaryentity = null;

            object listMetadata = null;

            if (entitytype == EntityName.TablePart)
            {
                listMetadata = InvokeObjectMethod(Metadata, EntityName.Document, entityname);
            }
            else
            {
                listMetadata = InvokeObjectMethod(Metadata, entitytype, entityname);
            }

            object manager = null;
            string createcommand = "";

            if (String.IsNullOrEmpty(ent.Id))
            {
                if (entitytype == EntityName.Catalog || entitytype == EntityName.Document)
                {
                    manager = OSConnection.CreateObject(ent.Name);
                    createcommand = "Новый";
                }
                else if (entitytype == EntityName.TablePart)
                {
                    manager = OSConnection.CreateObject(String.Format("{0}.{1}", EntityName.Document, entityname));
                    object tmpManager = FromIdToObject(String.Format("{0}.{1}", EntityName.Document, GetEntityName(ent.Name)), (string)ent[EntityName.Document]);
                    InvokeObjectMethod(manager, "НайтиДокумент", tmpManager);

                    createcommand = "НоваяСтрока";
                }
                else if (entitytype == EntityName.Registry)
                {
                    throw new Exception("Entity type currently is not supported");
                }
                InvokeObjectMethod(manager, createcommand);
            }
            else
            {
                if (entitytype == EntityName.TablePart)
                {
                    if (ent.ContainsKey(EntityName.Document))
                    {
                        manager = FromIdToObject(String.Format("{0}.{1}", EntityName.Document, GetEntityName(ent.Name)), (string)ent[EntityName.Document]);
                        InvokeObjectMethod(manager, "ПолучитьСтрокуПоНомеру", new object[] { ent.Id.Split('/')[1] });
                    }
                    else
                    {
                        return null;
                    }
                }
                else
                {
                    manager = FromIdToObject(ent.Name, ent.Id);
                }
            }

            foreach (var attribute in ent)
            {
                try
                {
                    string attributeType = GetAttributeType(listMetadata, entitytype, attribute.Key);

                    if (attributeType == DataType.String || attributeType == DataType.Number)
                    {
                        InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, attribute.Value });
                    }
                    else if (attributeType == DataType.Date)
                    {
                        InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, 
                                                                                                DateTime.Parse((string)attribute.Value).ToString("yyyyMMddhhmmss") });
                    }
                    else
                    {
                        if (attribute.Value is String)
                        {
                            if (!String.IsNullOrEmpty(attribute.Value.ToString()))
                            {
                                InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, 
                                                                                                        FromIdToObject((string)attribute.Value) });
                            }
                        }
                        else if (attribute.Value != null)
                        {
                            InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, attribute.Value });
                        }
                    }
                }
                catch (Exception ex)
                {
                    if (attribute.Key == "ДатаДок" || attribute.Key == "Дата" || attribute.Key == "Период")
                    {
                        InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, attribute.Value });
                    }
                    else if (attribute.Key == "НомерДок" || attribute.Key == "Номер" || attribute.Key == "Код" || attribute.Key == "Наименование")
                    {
                        InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, attribute.Value });
                    }
                    else if (attribute.Key == "Родитель" || attribute.Key == "Владелец")
                    {
                        InvokeObjectMethod(manager, "УстановитьАтрибут", new object[] { attribute.Key, FromIdToObject((string)attribute.Value) });
                    }
                }
            }

            return manager;
        }

        /// <summary>
        /// Gets number of rows in table part
        /// </summary>
        /// <param name="entity">COM object</param>
        /// <param name="tablename">Name of table part</param>
        /// <returns>Count.ToString()</returns>
        public string getRowCount(object entity, string tablename)
        {
            int count = (int)(double)InvokeObjectMethod(entity, "КоличествоСтрок", null);
            return count.ToString();
        }

        /// <summary>
        /// Gets list (перечисление) COM object by its string representation
        /// </summary>
        /// <param name="list">List name</param>
        /// <param name="value">List representation</param>
        /// <returns>COM object</returns>
        public object lookupListByValue(string list, string value)
        {
            var listi = GetObjectProperty(OSConnection, EntityName.Enumeration);
            var list1 = GetObjectProperty(listi, list);
            var val = GetObjectProperty(list1, value);

            return val;
        }

        /// <summary>
        /// Gets list (перечисление) name by Id
        /// </summary>
        /// <param name="id">List Id</param>
        /// <returns>List name</returns>
        public string getListName(string id)
        {
            var obj = FromIdToObject(id);

            var vid = InvokeObjectMethod(obj, "Вид");
            var lid = InvokeObjectMethod(obj, "Идентификатор");

            var metadata = GetObjectProperty(OSConnection, "Метаданные");
            var listMetadata = InvokeObjectMethod(metadata, EntityName.Enumeration, vid);

            var valueMetadata = InvokeObjectMethod(listMetadata, "Значение", lid);

            var result = InvokeObjectMethod(valueMetadata, "Представление");

            return result;
             
        }

        /// <summary>
        /// Gets field value by entity Id
        /// </summary>
        /// <param name="id">Id of entity</param>
        /// <param name="field">Field name</param>
        /// <returns>Field value</returns>
        public string lookupFieldById(string id, string field)
        {
            var obj = FromIdToObject( id ); ;

            object value = GetObjectProperty(obj, field);

            if (field == "Проведен" && value is string && String.IsNullOrEmpty((string)value))
            {
                value = (double)InvokeObjectMethod(obj, "Проведен") == 1.0;
            }

            if (value is bool || value is string || value is int || value is double || value is decimal || value is DateTime)
            {
                value = value.ToString();
            }
            else
            {
                value = (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { value });
            }

            return value.ToString();
        }

        /// <summary>
        /// Returns fields of specified entity
        /// </summary>
        /// <param name="ent">Entity containing Id</param>
        /// <param name="fields">Fields list to return</param>
        public void lookupFieldsById(Entity ent, string[] fields)
        {
            var obj = FromIdToObject(ent.Id);

            foreach (var field in fields)
            {
                object value = GetObjectProperty(obj, field);
                if (value is string || value is int || value is decimal || value is DateTime)
                {
                    ent.Add(field, value.ToString());
                }
                else
                {
                    ent.Add(field, (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { value }));
                }
            }
        }

        /// <summary>
        /// Searchs dictionary element by field value
        /// </summary>
        /// <param name="dictionary">Name of dictionary</param>
        /// <param name="field">Field name</param>
        /// <param name="value">Field value</param>
        /// <returns>Id of founded object</returns>
        public string lookupDictionaryByField(string dictionary, string field, string value)
        {
            return lookupDictionaryByField(dictionary, field, value, null);
        }

        /// <summary>
        /// Searchs dictionary element by field value
        /// </summary>
        /// <param name="dictionary">Name of dictionary</param>
        /// <param name="field">Field name</param>
        /// <param name="value">Field value</param>
        /// <param name="parent">Parent entity for subordinade</param>
        /// <returns>Id of founded object</returns>     
        public string lookupDictionaryByField(string dictionary, string field, string value, string parent)
        {
            var manager = OSConnection.CreateObject(dictionary);
            object result = null;

            if (!String.IsNullOrEmpty(parent))
            {
                SetObjectProperty(manager, "Владелец", OSConnection.ЗначениеИзСтрокиВнутр(parent));
            }

            if (field == "Код")
            {
                result = InvokeObjectMethod(manager, "НайтиПоКоду", new object[] { value });
            }
            else if (field == "Наименование")
            {
                result = InvokeObjectMethod(manager, "НайтиПоНаименованию", new object[] { value });
            }
            else if (field == "НомерДок")
            {
                result = InvokeObjectMethod(manager, "НайтиПоНомеру", new object[] { value, OSConnection.EvalExpr("ТекущаяДата()") });
            }
            else
            {
                result = InvokeObjectMethod(manager, "НайтиПоРеквизиту", new object[] { field, value, 1 });
            }

            string currentElementCommand = String.Empty;

            if (GetEntityType(dictionary) == EntityName.Document)
	        {
		        currentElementCommand = "ТекущийДокумент";
	        }
            else
            {
                currentElementCommand = "ТекущийЭлемент";
            }

            return (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { InvokeObjectMethod(manager, currentElementCommand) });
        }

        /// <summary>
        /// Ger list of objects by entity name
        /// </summary>
        /// <param name="entityName">Name of entity - for example "Справочники.Контрагенты"</param>
        /// <returns>Table of found objects</returns>
        public DataTable getObjectList(string entityName)
        {
            var result = new DataTable();
            result.Columns.Add("objectid");
            result.Columns.Add("name");

            string entitytype = entityName.Split(new char[] { '.' })[0];
            string nameField = String.Empty;
            string selectField = String.Empty;
            string nextField = String.Empty;

            if (entitytype == EntityName.Catalog)
            {
                nameField = "Наименование";
                selectField = "ВыбратьЭлементы";
                nextField = "ПолучитьЭлемент";
            }
            else if (entitytype == EntityName.Document)
            {
                nameField = "Номер";
                selectField = "ВыбратьДокументы";
                nextField = "ПолучитьДокумент";
            }
            else
            {
                throw new Exception("1C Object not supported");
            }

            /*ВыборкаСправочника = Справочники.Валюты.Выбрать();
Пока ВыборкаСправочника.Следующий() Цикл
    Сообщить("Записана валюта " + ВыборкаСправочника.Наименование);
КонецЦикла;*/
            var managerlist = OSConnection.CreateObject(entityName);

            InvokeObjectMethod(managerlist,selectField);
            
            while ((double)InvokeObjectMethod(managerlist, nextField) == 1.0)
            {
                var row = result.NewRow();
                row["objectid"] = InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { InvokeObjectMethod(managerlist, "ТекущийЭлемент") });
                row["name"] = GetObjectProperty(managerlist, nameField);
                result.Rows.Add(row);
            }

            return result;
        }

        /// <summary>
        /// Markes entity as deleted or removes string from document
        /// </summary>
        /// <param name="entity">Object to delete</param>
        public void Delete(Entity entity)
        {
            string entitytype = GetEntityType(entity.Name);
            object osEntity = null;

            if (!String.IsNullOrEmpty(entity.Id))
            {
                if (entitytype == EntityName.TablePart)
                {
                    string entityname = GetEntityName(entity.Name);

                    osEntity = FromIdToObject(EntityName.Document + "." + entityname, entity.Id.Split('/')[0]);
                    InvokeObjectMethod(osEntity, "ПолучитьСтрокуПоНомеру", entity.Id.Split('/')[1]);
                    InvokeObjectMethod(osEntity, "УдалитьСтроку");
                    SaveEntity(osEntity);
                }
                else
                {
                    osEntity = FromIdToObject(entity.Name, entity.Id );
                    InvokeObjectMethod(osEntity, "Удалить", 0);
                    SaveEntity(osEntity);
                }
            }
        }

        /// <summary>
        /// Moves 1C document
        /// </summary>
        /// <param name="entity">1C document entity represented by COM object</param>
        public void MoveDocument(object entity)
        {
            var move = InvokeObjectMethod(entity, "Провести");

            if ((double) move != 1.0)
            {
                throw new Exception("Документ не проведен!");
            }
        }

        /// <summary>
        /// Declines document move
        /// </summary>
        /// <param name="entity">1C document represented by COM object</param>
        public void UnMoveDocument(object entity)
        {
            InvokeObjectMethod(entity, "СделатьНеПроведенным");
        }

        /// <summary>
        /// Stores 1C entity calling Save function
        /// </summary>
        /// <param name="entity">COM object, representing 1C object</param>
        /// <returns></returns>
        public string SaveEntity(object entity)
        {
            try
            {
                InvokeObjectMethod(entity, "Записать", new Object[] { true });
            }
            catch
            {
                InvokeObjectMethod(entity, "Записать", null);
            }
            string id = String.Empty;

            try
            {
                id = (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { InvokeObjectMethod(entity, "ТекущийЭлемент") });
            }
            catch 
            {
                try
                {
                    id = (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new Object[] { InvokeObjectMethod(entity, "ТекущийДокумент") });
                }
                catch { };
            };
            return id;
        }

        /// <summary>
        /// Gets type of attribute represented by COM object of Metadata type
        /// </summary>
        /// <param name="recv">Attribute COM object</param>
        /// <returns></returns>
        private string getType(object recv)
        {
            throw new NotImplementedException();

            object types = GetObjectProperty(recv, "Тип");
            object typ = InvokeObjectMethod(types, "Типы", new object[] { });
            object typing = InvokeObjectMethod(typ, "Получить", new object[] { 0 });
            return (string)InvokeObjectMethod(OSConnection, "String", new object[] { typing });
        }

        /// <summary>
        /// Gets type of attribute
        /// </summary>
        /// <param name="entitytype">Type of entity, for example "Справочник"</param>
        /// <param name="entityname">Name of entity, for example "Контрагент"</param>
        /// <param name="attribute">Name of attribute</param>
        /// <returns></returns>
        public string GetAttributeType(object entityMetadata, string entitytype, string attribute)
        {
            string type = String.Empty;
            object recv = null;

            if (entitytype == EntityName.Catalog)
            {
                recv = InvokeObjectMethod(entityMetadata, AttributeType.Property, attribute);
            }
            else if (entitytype == EntityName.Document)
            {
                recv = InvokeObjectMethod(entityMetadata, AttributeType.HeaderProperty, attribute);

                try
                {
                    GetObjectProperty(recv, "Идентификатор");
                }
                catch
                {
                    recv = InvokeObjectMethod(Metadata, AttributeType.GeneralDocumentProperty, attribute);
                }
            }
            else if (entitytype == EntityName.Registry)
            {
                string attributetype = attribute.Split('.')[0];
                string attributename = attribute.Split('.')[1];

                recv = InvokeObjectMethod(entityMetadata, attributetype, attributename);
            }
            else if (entitytype == EntityName.TablePart)
            {
                recv = InvokeObjectMethod(entityMetadata, AttributeType.TableProperty, attribute);
            }

            return (string)GetObjectProperty(recv, "Тип");
        }

        /// <summary>
        /// Get 1C objects by fiter
        /// </summary>
        /// <param name="filter">Filter contains info about criterias and attributes list to return</param>
        /// <returns></returns>
        public List<Entity> getObjects(Filter filter)
        {
            throw new NotImplementedException();

            /*List<Entity> result = new List<Entity>();

            string entitytype = filter.entity.Split(new char[] { '.' })[0];
            string entityname = filter.entity.Split(new char[] { '.' })[1];
            string tablename = String.Empty;

            switch (entitytype)
            {
                case "РегистрыСведений":
                    tablename = "РегистрСведений.";
                    break;
                case "РегистрыНакопления":
                    tablename = "РегистрНакопления.";
                    break;
                case "Справочники":
                    tablename = "Справочник.";
                    break;
                case "Документы":
                    tablename = "Документ.";
                    break;
                default:
                    break;
            }
            tablename += entityname;

            StringBuilder queryText = new StringBuilder("ВЫБРАТЬ ");

            bool coma = false;
            if (filter.attributes.Count > 0)
            {
                foreach (CAttribute attribute in filter.attributes)
                {
                    if (coma)
                    {
                        queryText.Append(",");
                    }
                    queryText.Append(attribute.name);
                    coma = true;
                }
                if (entitytype != "РегистрыСведений" && entitytype != "РегистрыНакопления")
                {
                    queryText.Append("," + tablename + ".Ссылка КАК Ссылка");
                }
            }
            else
            {
                if (entitytype != "РегистрыСведений" && entitytype != "РегистрыНакопления")
                {
                    queryText.Append(tablename + ".Ссылка КАК Ссылка");
                }
                else
                {
                    queryText.Append("*");
                }
            }

            queryText.AppendFormat(" ИЗ {0}", tablename);

            if (filter.conditions.Count > 0)
            {
                queryText.Append(" ГДЕ ");
                bool and = false;
                foreach (CCondition condition in filter.conditions)
                {
                    if (and)
                    {
                        queryText.Append(" И ");
                    }
                    queryText.AppendFormat("{0} {1} &{0}", condition.attribute, condition.opr);

                    and = true;
                }
            }

            var request = InvokeObjectMethod(OSConnection, "NewObject", new object[] { "Запрос" });
            SetObjectProperty(request, "Текст", queryText.ToString());

            foreach (CCondition condition in filter.conditions)
            {
                string num = getAttributeType(entitytype, entityname, condition.attribute);
                //Запрос.УстановитьПараметр("Владелец", Контрагент); 
                if (num == "Строка" || num == "String")
                {
                    InvokeObjectMethod(request, "УстановитьПараметр", new object[] { condition.attribute, condition.value });
                }
                else if (num == "Число" || num == "Number")
                {
                    InvokeObjectMethod(request, "УстановитьПараметр", new object[] { condition.attribute, condition.value });
                }
                else if (num == "Дата" || num == "Date")
                {
                    InvokeObjectMethod(request, "УстановитьПараметр", new object[] { condition.attribute, condition.value });
                }
                else if (num == "Булево" || num == "Boolean")
                {
                    InvokeObjectMethod(request, "УстановитьПараметр", new object[] { condition.attribute, condition.value });
                }
                else
                {
                    InvokeObjectMethod(request, "УстановитьПараметр", new object[] { condition.attribute, InvokeObjectMethod(OSConnection, "ЗначениеИзСтрокиВнутр", new object[] { condition.value }) });
                }

            }

            var reqResult = InvokeObjectMethod(request, "Выполнить");

            var requestGoThrowConst = GetObjectProperty(OSConnection, "ОбходРезультатаЗапроса");
            var groupConst = GetObjectProperty(requestGoThrowConst, "ПоГруппировкам");
            var directConst = GetObjectProperty(requestGoThrowConst, "Прямой");

            var select = InvokeObjectMethod(reqResult, "Выбрать", new object[] { directConst });
            //select = InvokeObjectMethod(select, "Выбрать", new object[] { directConst });

            var columns = GetObjectProperty(reqResult, "Колонки");
            int colcount = (int)InvokeObjectMethod(columns, "Количество");

            while ((bool)InvokeObjectMethod(select, "Следующий"))
            {
                Entity ent = new Entity()
                {
                    Name = filter.entity,
                    System = filter.connection
                };

                for (int i = 0; i < colcount; i++)
                {
                    var column = InvokeObjectMethod(columns, "Получить", new object[] { i });
                    string columnName = (string)GetObjectProperty(column, "Имя");

                    if (columnName == "Ссылка")
                    {
                        ent.Id = (string)InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new object[] { GetObjectProperty(select, columnName) });
                    }
                    else
                    {
                        string num = getAttributeType(entitytype, entityname, columnName);
                        //Запрос.УстановитьПараметр("Владелец", Контрагент); 
                        if (num == "Строка" || num == "String")
                        {
                            ent.Add(columnName, GetObjectProperty(select, columnName).ToString());
                        }
                        else if (num == "Число" || num == "Number")
                        {
                            ent.Add(columnName, GetObjectProperty(select, columnName).ToString());
                        }
                        else if (num == "Дата" || num == "Date")
                        {
                            ent.Add(columnName, GetObjectProperty(select, columnName).ToString());
                        }
                        else if (num == "Булево" || num == "Boolean")
                        {
                            ent.Add(columnName, GetObjectProperty(select, columnName).ToString());
                        }
                        else
                        {
                            ent.Add(columnName, InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new object[] { GetObjectProperty(select, columnName) }).ToString());
                        }

                        if (ent.ContainsKey("type"))
                        {
                            ent["type"] = num;
                        }
                        else
                        {
                            ent.Add("type", num);
                        }
                    }
                }

                result.Add(ent);
            }

            return result;*/
        }

        #region Methods for working with COM Objects

        public object SetObjectProperty(object refObject, string propertyName, object value)
        {
            /*try
            {*/
            object[] arg = new object[] { value };
            return refObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, refObject, arg);
            /*}
            catch (Exception ex)
            {
                string s = (string)InvokeObjectMethod(OSConnection, "ОписаниеОшибки");
                throw new Exception(s);
            }*/
        }

        public object GetObjectProperty(object refObject, string propertyName, object[] args)
        {
            /*try
            {*/
            return refObject.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, refObject, args);
            /*}
            catch (Exception ex)
            {
                string s = (string)InvokeObjectMethod(OSConnection, "ОписаниеОшибки");
                throw new Exception(s);
            }*/
        }

        public object GetObjectProperty(object v82, object refObject, string propertyName)
        {
            /*try
            {*/
            return v82.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, refObject, null);
            /*}
            catch (Exception ex)
            {
                string s = (string)InvokeObjectMethod(OSConnection, "ОписаниеОшибки");
                throw new Exception(s);
            }*/
        }

        public object GetObjectProperty(object refObject, string propertyName)
        {
            /*try
            {*/
            return refObject.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, refObject, null);
            /*}
            catch (Exception ex)
            {
                string s = (string)InvokeObjectMethod(OSConnection, "ОписаниеОшибки");
                throw new Exception(s);
            }*/
        }

        public object InvokeObjectMethod(object v82, object refObject, string methodName, Object[] parameters)
        {
            return v82.GetType().InvokeMember(methodName, BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, refObject, parameters);
        }

        public object InvokeObjectMethod(object refObject, string methodName, Object[] parameters)
        {
            return refObject.GetType().InvokeMember(methodName, BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, refObject, parameters);
        }

        public object InvokeObjectMethod(object refObject, string methodName)
        {
            return refObject.GetType().InvokeMember(methodName, BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Static, null, refObject, null);
        }

        public object InvokeObjectMethod(object refObject, string methodName, object parameter)
        {
            return InvokeObjectMethod(refObject, methodName, new object[] { parameter });
        }
        
        #endregion

        #region Helper methods

        /// <summary>
        /// Get COM object based on id of that object
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public object FromIdToObject(string id)
        {
            object obj = InvokeObjectMethod(OSConnection, "ЗначениеИзСтрокиВнутр", new object[] { id, null });

            try
            {
                obj = InvokeObjectMethod(obj, "ТекущийЭлемент");
            }
            catch
            {
                try
                {
                    obj = InvokeObjectMethod(obj, "ТекущийДокумент");
                }
                catch { };
            }

            return obj;
        }

        /// <summary>
        /// Get COM object based on id and entity name of that object
        /// </summary>
        /// <param name="id">1C id of object</param>
        /// <returns></returns>
        public object FromIdToObject(string entity, string id)
        {
            /*Ном = Соединение77.Норм_Параметр.ТекущийЭлемент();
НомДляЗаписи = Соединение77.CreateObject("Справочник.ЧегоТоТам");
Если НомДляЗаписи.НайтиЭлемент(Ном.ТекущийЭлемент()) = 1 Тогда*/

            object obj = InvokeObjectMethod(OSConnection, "ЗначениеИзСтрокиВнутр", new object[] { id, null });

            if (GetEntityType(entity) == EntityName.Catalog)
            {
                obj = InvokeObjectMethod(obj, "ТекущийЭлемент");
                object manager = InvokeObjectMethod(OSConnection, "CreateObject", entity);
                if ((double)InvokeObjectMethod(manager, "НайтиЭлемент", obj) == 1)
                {
                    obj = manager;
                }
            }
            else if (GetEntityType(entity) == EntityName.Document)
            {
                obj = InvokeObjectMethod(obj, "ТекущийДокумент");
                object manager = InvokeObjectMethod(OSConnection, "CreateObject", entity);
                if ((double)InvokeObjectMethod(manager, "НайтиДокумент", obj) == 1)
                {
                    obj = manager;
                };
            }

            return obj;
        }

        /// <summary>
        /// Get internal id of 1C object
        /// </summary>
        /// <param name="obj">COM Object that represents 1C Object</param>
        /// <returns></returns>
        public string FromObjectToId(object obj)
        {
            return InvokeObjectMethod(OSConnection, "ЗначениеВСтрокиВнутр", obj);
        }

        public string GetEntityType(string entity)
        {
            return entity.Split('.')[0];
        }

        public string GetEntityName(string entity)
        {
            return entity.Split('.')[1];
        }

        #endregion

        /// <summary>
        /// Checks if 1C COM object is available
        /// </summary>
        /// <returns>true if available</returns>
        public override HealthInfo CheckHealth()
        {
            var healthInfo = new HealthInfo()
            {
                ServiceName = GetType().FullName,
            };

            try
            {
                var manager = GetObjectProperty(OSConnection, "Метаданные");
                healthInfo.Status = true;
            }
            catch (Exception ex)
            {
                close();
                healthInfo.Status = false;
                healthInfo.ErrorInfo = ex.Message;
            }

            return healthInfo;
        }

        /// <summary>
        /// Closes connection to 1C COM Object
        /// </summary>
        public override void close()
        {
            _OSConnection = null;
            GC.Collect();
        }

        /// <summary>
        /// Gets value of entity attribute based on COM Object
        /// </summary>
        /// <param name="entity">COM object containing 1C object</param>
        /// <param name="entityType">Type of Entity, for exmple "Справочники" or "ТабличныеЧасти"</param>
        /// <param name="emtityName">Name of entity, for example "Контрагенты"</param>
        /// <param name="columnName">Name of field</param>
        /// <returns></returns>
        public string getEntityAttributeValue(object entity, string entityType, string emtityName, string columnName)
        {
            throw new NotImplementedException();
            /*
            try
            {
                string num = getAttributeType(entityType, emtityName, columnName);

                string result;

                //Запрос.УстановитьПараметр("Владелец", Контрагент); 
                if (num == "Строка" || num == "String" || num == "Число" || num == "Number" || num == "Дата" || num == "Date" || num == "Булево" || num == "Boolean")
                {
                    result = GetObjectProperty(entity, columnName).ToString();
                }
                else
                {
                    result = InvokeObjectMethod(OSConnection, "ЗначениеВСтрокуВнутр", new object[] { GetObjectProperty(entity, columnName) }).ToString();
                }

                return result;
            }
            catch (Exception ex)
            {
                throw new Exception(String.Format("Error getting value of attribute {0} : {1}", columnName, ex.Message));
            }
            */
        }
    }
}
